package com.wsoft.oss.config;

import com.wsoft.constant.ConfigConstant;
import com.wsoft.core.service.CommonConfigService;
import com.wsoft.core.vo.ConfigQuery;
import com.wsoft.oss.constant.OssConstant;
import com.wsoft.oss.service.impl.OssLocalServiceImpl;
import com.wsoft.oss.service.impl.OssMinioServiceImpl;
import com.wsoft.oss.utils.MinioTemplate;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 自定义 动态注册bean
 * @Author z001
 * @Date 2024/12/12 14:57
 */
@Component
public class OssBeanRegistrar implements CommandLineRunner {

    @Autowired
    private CommonConfigService commonConfigService;
    private final BeanFactory beanFactory;
    public OssBeanRegistrar(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void run(String... args) {
        Map<String, String> fileMap = getFileMap(commonConfigService);
        String fileType = fileMap.get(ConfigConstant.OSS_TYPE);


        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

        // 如果 file.type 为 minio，则注册相关 Bean
        if (OssConstant.UPLOAD_TYPE_MINIO.equals(fileType)) {
            // 注册 MinioClient
            registerMinioClient(registry,fileMap);

            // 注册 MinioTemplate
            registerMinioTemplate(registry);

            // 注册 OssMinioServiceImpl
            registerOssMinioService(registry);
        }else{
            // 注册 OssLocalServiceImpl
            registerOssLocalService(registry,fileMap);
        }

    }


    /**
     * 注册 MinioClient
     * @param registry
     */
    private void registerMinioClient(BeanDefinitionRegistry registry,Map<String, String> fileMap) {
        // 从数据库中读取 Minio 配置
        MinioProperties minioProperties  = new MinioProperties();
        minioProperties.setEndpoint(fileMap.get(ConfigConstant.MINIO_ENDPOINT));
        minioProperties.setAccessKey(fileMap.get(ConfigConstant.MINIO_ACCESS_KEY));
        minioProperties.setSecretKey(fileMap.get(ConfigConstant.MINIO_SECRET_KEY));
        minioProperties.setBucketNamePublic(OssConstant.OSS_BUCKET_PUBLIC);
        minioProperties.setBucketNameLogin(OssConstant.OSS_BUCKET_LOGIN);
        minioProperties.setBucketNameAuthority(OssConstant.OSS_BUCKET_AUTHORITY);
        minioProperties.setBreakpointTime(OssConstant.OSS_BREAKPOINT_TIME);

        // 创建 MinioClient BeanDefinition
        BeanDefinitionBuilder minioClientBuilder = BeanDefinitionBuilder.rootBeanDefinition(MinioClient.class, () -> {
            MinioClient client = MinioClient.builder()
                    .endpoint(minioProperties.getEndpoint())
                    .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                    .build();

            // 检查并创建 bucket
            try {
                createBucketIfNotExists(client, minioProperties.getBucketNamePublic());
                createBucketIfNotExists(client, minioProperties.getBucketNameLogin());
                createBucketIfNotExists(client, minioProperties.getBucketNameAuthority());

            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            return client;
        });

        // 注册 MinioClient Bean
        registry.registerBeanDefinition("minioClient", minioClientBuilder.getBeanDefinition());
    }

    /**
     * 注册 MinioTemplate
     * @param registry
     */
    private void registerMinioTemplate(BeanDefinitionRegistry registry) {
        // 创建 MinioTemplate BeanDefinition
        BeanDefinitionBuilder minioTemplateBuilder = BeanDefinitionBuilder.rootBeanDefinition(MinioTemplate.class);

        // 设置 MinioTemplate 依赖 MinioClient
        minioTemplateBuilder.addConstructorArgReference("minioClient");

        // 注册 MinioTemplate Bean
        registry.registerBeanDefinition("minioTemplate", minioTemplateBuilder.getBeanDefinition());
    }

    /**
     * OssMinioServiceImpl
     * @param registry
     */
    private void registerOssMinioService(BeanDefinitionRegistry registry) {
        // 创建 OssMinioServiceImpl BeanDefinition
        BeanDefinitionBuilder ossMinioServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(OssMinioServiceImpl.class);

        // 设置 OssMinioServiceImpl 依赖 MinioTemplate
        ossMinioServiceBuilder.addConstructorArgReference("minioTemplate");

        // 注册 OssMinioServiceImpl Bean
        registry.registerBeanDefinition("ossMinioService", ossMinioServiceBuilder.getBeanDefinition());
    }

    /**
     * OssLocalServiceImpl
     * @param registry
     */
    private void registerOssLocalService(BeanDefinitionRegistry registry,Map<String, String> fileMap) {
        // 创建 OssLocalServiceImpl BeanDefinition
        BeanDefinitionBuilder ossLocalServiceBuilder = BeanDefinitionBuilder.rootBeanDefinition(OssLocalServiceImpl.class);

        String localPath =  fileMap.get(ConfigConstant.LOCAL_PATH);
        Long maxSize = Long.valueOf(fileMap.get(ConfigConstant.OSS_MAXIMUM_LIMIT));
        String storageType = OssConstant.UPLOAD_TYPE_LOCAL;

        // 为构造函数传参
        ossLocalServiceBuilder.addConstructorArgValue(localPath);
        ossLocalServiceBuilder.addConstructorArgValue(storageType);
        ossLocalServiceBuilder.addConstructorArgValue(maxSize);

        // 注册 OssLocalServiceImpl Bean
        registry.registerBeanDefinition("ossLocalService", ossLocalServiceBuilder.getBeanDefinition());
    }


    private void createBucketIfNotExists(MinioClient client, String bucketName) throws Exception {
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }


    public  Map<String, String> getFileMap( CommonConfigService commonConfigService){
        ConfigQuery query = new ConfigQuery();
        query.setCode(ConfigConstant.OSS_CONFIG_FILE);
        return commonConfigService.getConfigValue(query);
    }


}
